home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
utility
/
btoa52.zip
/
ATOB.C
next >
Wrap
C/C++ Source or Header
|
1994-04-08
|
10KB
|
403 lines
/* atob.c */
/* Written by Paul Rutter, Joe Orost & Stefan Parmark. */
#include <stdio.h>
#ifdef AMIGA
#include <stdlib.h>
#include <string.h>
#endif AMIGA
#include "btoa.h"
#if USE_MACROS
#include "chksum.h"
#endif USE_MACROS
BYTE atob(infile)
register FILE *infile;
{
register BYTE error;
register LONG filepos;
int maxperline;
LONG n1, n2, oeor, osum, orot, lastline;
static BYTE outfilename[BUFSIZE];
extern LONG Ceor, Csum, Crot;
extern FILE *outfile;
extern BYTE new_version, openoutput, buffer[BUFSIZE];
error = FALSE;
/* Search for archive header. */
do
{
filepos = ftell(infile);
if (readbuffer(buffer, "archive", infile))
error = TRUE;
}
while (!(error || strncmp(buffer, "xbtoa", 5) == 0));
if (!error)
if (strcmp(buffer, "xbtoa Begin\n") == 0)
{
new_version = FALSE;
fprintf(stderr, "btoa: Old btoa format.\n");
}
else if (sscanf(buffer, "xbtoa5 %d %s Begin\n", &maxperline, outfilename) == 2)
{
new_version = TRUE;
/* Naming a file overrides the read-name-from-file function. */
if (!openoutput && strcmp(outfilename, "-") != 0)
if ((outfile = fopen_write(outfilename)) == NULL)
error = TRUE;
else
openoutput = TRUE;
}
else
{
fprintf(stderr, "btoa: Illegal archive header.\n");
error = TRUE;
}
if (!error)
{
Ceor = Csum = Crot = 0;
if (new_version)
error = new_decodefile(infile, &lastline, filepos, maxperline);
else
error = old_decodefile(infile, &lastline);
}
if (!error)
{
if (sscanf(buffer, "xbtoa End N %ld %lx E %lx S %lx R %lx\n",
&n1, &n2, &oeor, &osum, &orot) != 5)
{
fprintf(stderr, "btoa: Bad format on line %ld. Can't repair file.\n",
lastline);
error = TRUE;
}
else if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot))
{
fprintf(stderr, "btoa: Bad file checksum. Can't repair file.\n");
error = TRUE;
}
else
/* Flush last characters. */
decode_line(NULL, (int) ((n1 - 1) & 0x03));
}
return(error);
}
/* Peek at the next byte without moving the file pointer. */
int nextbyte(infile)
register FILE *infile;
{
register int ch;
register LONG filepos;
filepos = ftell(infile);
ch = fgetc(infile);
fseek(infile, filepos, 0);
return(ch);
}
BYTE new_decodefile(infile, lastline, filepos, maxperline)
register FILE *infile;
LONG *lastline, filepos;
int maxperline;
{
register int length;
int ch;
register BYTE stop, error, newerror, errorstart;
register LONG line, prevfilepos, startpos;
struct Diagnosis diagnosislist;
extern LONG Csum;
extern BYTE buffer[BUFSIZE];
error = FALSE;
line = 1; /* Current line number. */
/* A sequence of errors is indicated by errorstart. When it */
/* changes from TRUE to FALSE a diagnosis record will be */
/* generated. */
stop = errorstart = FALSE;
/* File position of the line before the error sequence. */
/* That is the last correct line. */
startpos = 0;
while (!stop)
{
prevfilepos = filepos;
filepos = ftell(infile);
/* Newerror indicates an error on the current line. */
newerror = FALSE;
line++;
if (readbuffer(buffer, "archive", infile))
newerror = stop = TRUE;
else if (buffer[0] == 'x') /* End of archive found. */
stop = TRUE;
else if ((length = strlen(buffer) - 1) != maxperline ||
buffer[length] != '\n')
{
/* If last character wasn't end-of-line, then we */
/* have to read until it is found. */
if (buffer[length] != '\n')
{
newerror = TRUE;
while ((ch = fgetc(infile)) != EOF && (BYTE)ch != '\n')
;
if (ch == EOF)
stop = TRUE;
}
else if (length > maxperline || nextbyte(infile) != 'x')
{
newerror = TRUE;
Csum = DECODE(buffer[length - 1]); /* Make Csum correct (modulo 85). */
}
if (newerror)
fprintf(stderr, "btoa: Bad line length on line %ld.\n", line);
}
if (!(newerror || stop))
{
if (decode_line(buffer, length - 1))
{
if (!error)
fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
newerror = TRUE;
}
/* Examine checksum. */
if ((ch = buffer[length - 1]) == ENCODE(Csum % 85))
{
if (errorstart)
{
intodiagnosislist(&diagnosislist, startpos, filepos);
errorstart = FALSE;
}
}
else
{
newerror = TRUE;
fprintf(stderr, "btoa: Bad checksum on line %ld.\n", line);
Csum = DECODE(ch); /* Make Csum correct (modulo 85). */
}
}
if (newerror)
{
if (!error)
{
fprintf(stderr, "btoa: Starting diagnosis.\n");
diagnosislist.next = diagnosislist.last = NULL;
}
error = TRUE;
if (!errorstart)
{
errorstart = TRUE;
startpos = prevfilepos;
}
}
}
if (error)
{
if (errorstart)
intodiagnosislist(&diagnosislist, startpos, filepos);
producediagnosis(&diagnosislist, infile);
}
*lastline = line;
return(error);
}
BYTE old_decodefile(infile, lastline)
register FILE *infile;
LONG *lastline;
{
register int length;
register BYTE stop, error;
register LONG line;
extern BYTE buffer[BUFSIZE];
error = FALSE;
line = 1;
stop = FALSE;
while (!stop)
{
line ++;
if (readbuffer(buffer, "archive", infile))
error = stop = TRUE;
else if (buffer[0] == 'x') /* End of archive found. */
stop = TRUE;
else
{
length = strlen(buffer) - 1;
if (buffer[length] != '\n')
error = stop = TRUE; /* The line was longer than the buffer. */
}
if (!stop)
{
if (decode_line(buffer, length))
{
fprintf(stderr, "btoa: Bad character on line %ld.\n", line);
error = stop = TRUE;
}
}
}
*lastline = line;
return(error);
}
BYTE decode_line(buffer, length)
register BYTE *buffer;
register int length;
{
register int ch;
register BYTE error;
register LONG tmp_codeword;
extern BYTE new_version;
extern FILE *outfile;
static LONG codeword;
static int ch1, ch2, ch3, ch4;
static BYTE bytecount = 0;
error = FALSE;
if (buffer == NULL) /* Flush last characters. */
{
if (bytecount > 0)
{
fputc(ch1, outfile);
if (length > 0)
fputc(ch2, outfile);
if (length > 1)
fputc(ch3, outfile);
if (length > 2)
fputc(ch4, outfile);
}
}
else
{
while (length > 0)
{
length--;
ch = *buffer++;
/* Delayed output. This is to make sure that files with lengths */
/* that are not multiples of 4 won't become too long. */
if (bytecount == 5)
{
fputc(ch1, outfile);
fputc(ch2, outfile);
fputc(ch3, outfile);
fputc(ch4, outfile);
bytecount = 0;
}
if (new_version)
calcchecksum(ch);
if (((BYTE)ch >= '!') && ((BYTE)ch < ('!' + 85))) /* Valid characters. */
{
/* See if we can take all 5 bytes and decode them right away. */
/* That is, if all remaining bytes are on the current line. */
if (length >= 4 - bytecount)
{
length -= 4 - bytecount;
if (bytecount == 0)
codeword = DECODE(ch);
else
codeword = codeword * 85 + DECODE(ch);
for (bytecount++; bytecount < 5; bytecount++)
{
ch = *buffer++;
if (new_version)
calcchecksum(ch);
codeword = codeword * 85 + DECODE(ch);
}
}
else
{
/* Shift codeword and insert character. */
if (bytecount == 0)
{
codeword = DECODE(ch);
bytecount = 1;
}
else /* bytecount < 5 */
{
codeword = codeword * 85 + DECODE(ch);
bytecount ++;
}
}
if (bytecount == 5)
{
tmp_codeword = codeword;
ch4 = (int)tmp_codeword & 0xFF;
ch3 = (int)(tmp_codeword >>= 8) & 0xFF;
ch2 = (int)(tmp_codeword >>= 8) & 0xFF;
ch1 = (int)(tmp_codeword >> 8) & 0xFF;
if (!new_version)
{
calcchecksum(ch1);
calcchecksum(ch2);
calcchecksum(ch3);
calcchecksum(ch4);
}
}
}
else if ((BYTE)ch == 'z' || (new_version && (BYTE)ch == 'y'))
{
if (bytecount != 0)
error = TRUE;
else
{
ch1 = ch2 = ch3 = ch4 = (ch == 'z') ? 0 : ' ';
if (!new_version)
{
calcchecksum(ch1);
calcchecksum(ch1);
calcchecksum(ch1);
calcchecksum(ch1);
}
bytecount = 5;
}
}
else
error = TRUE;
}
}
return(error);
}